package org.dei.perla.sys.registry.datastructure;

import java.util.ArrayList;


/**
 * binary trees are used to store information on the FPC currently instantiated in the systems
 * for any attribute readable by an FPC (temperature, pressure, humidity.....) a binary tree is
 * instantiated. Each node of the tree has a key [a value of the attribute transmitted by the sensor(FPC)]
 * and a data (list of FPC with sensed the corresponding value of the key)
 * */
public class BTreeNode {

	/**
	 * The value of the attribute for the current node
	 */
	private BTreeData key;
	/**
	 * type of attribute stores at this node (humidity,pressure,......)
	 */
	private String attrType;
	
	/**
	 * list of FPC with last reading on the attribute 'attType' equal to the key value
	 *
	 */
	private ArrayList<BTreeData> data;
	/**
	 * node left child: has lower value for the key
	 */
	protected BTreeNode leftChild;
	/**
	 * node right child: has greater value for the key
	 */
	protected BTreeNode rightChild;
	
	/**
	 *  BTreeNode constructor 
	 * @param  for the root
	 * @param attribute the type of attribute indexed by the tree
	 */
	@SuppressWarnings("unchecked")
	public BTreeNode( FunctionalityProxyComponent fpc, String attribute){
		
		BTreeData elem = new BTreeData(attribute, fpc);
		this.key = elem;
		
		data = new ArrayList<BTreeData>();
		this.data.add(elem);
		this.attrType = attribute;
	}
	
	
	@SuppressWarnings("unchecked")
	public BTreeNode( BTreeData btree_data, String attribute){
		
		this.key=btree_data ;
		data = new ArrayList<BTreeData>() ;
		this.data.add((BTreeData)btree_data) ;
		this.attrType = attribute ;
	}
	
	
	/**
	 * @return true if the node has a left child, false otherwise
	 */
	public boolean has_left(){
		return (leftChild!=null);
	}
	/**
	 * @return true if the node has a right child, false otherwise
	 */
	public boolean has_right(){
		return (rightChild!=null);
	}
	/**
	 * getters=======================================================================
	 * @return ......................................................................
	 */
	
	public BTreeNode getRight(){
		return this.rightChild;
	}	
	public BTreeNode getleft(){
		return this.leftChild;
	}	
	public BTreeData getKey(){
		return this.key;
	}
	public String getAttrType(){
		return this.attrType;
	}
	public ArrayList<BTreeData> getAlldata(){
		return this.data;
	}
	
	/**.................................Non generic ..................................
	*/
	@SuppressWarnings("unchecked")
	//  getElem(int FPC_Id)
	public  FunctionalityProxyComponent getFPC (int FPC_Id){
	  		
		for (Comparable dataPtr: this.data){
			FunctionalityProxyComponent FPCPtr =((BTreeData)dataPtr).getFPC();
			if(FPCPtr.getID() == FPC_Id) return FPCPtr;
		}
		return null;
	}
	
	@SuppressWarnings("unchecked")
	//delete an element amont all the element at a tree
	public BTreeData getElement(int FPC_Id){
		
		for (BTreeData dataPtr: this.data){
			FunctionalityProxyComponent FPCPtr =dataPtr.getFPC();
			if(FPCPtr.getID() == FPC_Id) return dataPtr;
		}
		
		//what TODO? return null or throw Exc
		//throw new ElemNotFoundException("elemt not found at the current node");
		return null;
	}
	
	

	@SuppressWarnings("unchecked")
	//will be replaced by an indexing in the FPC ID
	public int deleteElement(int FPC_Id){
	 		
		for (Comparable dataPtr: this.data){
			FunctionalityProxyComponent FPCPtr =((BTreeData)dataPtr).getFPC();
			if(FPCPtr.getID() == FPC_Id){
				data.remove(dataPtr);
				if(data.size()>0) return 1;
				return 0;
			}
		}
		return -1;
	}
	
	/**
	 * @param elem
	 * @return
	 */
	private int deleteElement(BTreeData elem){
 		
		for (BTreeData dataPtr: this.data){
			if(dataPtr.getFPC().getID() == elem.getFPC().getID()){
				data.remove(dataPtr);
				if(data.size()>0) return 1;
				return 0;
			}
		}
		return -1;
	}
	
	/**
	 * setters=======================================================================
	 *...............................generic................................
	 */
	
	public void setRight(BTreeNode right){
		this.rightChild = right ;
	}
	public void  setleft(BTreeNode left){
		this.leftChild = left;
	}
	
	public  void setKey(BTreeData key){
		this.key = key ;
	}
	public void setAttrType(String attr_type){
		this.attrType = attr_type;
	}
	public void reaAllocAlldata(ArrayList<BTreeData> newdata){
		this.data.clear();
		this.data.addAll(newdata) ;
		this.key = this.data.get(0);
	}
	
	public void setAlldata(ArrayList<BTreeData> newdata){
		this.data = newdata;
		this.key = this.data.get(0);
	}
	
	public boolean isEmpty(){
		return (this.data.size() <=0);
	}
	
	public boolean hasOneElem(){
		return (this.data.size() ==1);
	}
	
	/**............................ Non generic ................................................
	 * */
	
	/**
	 * @param fpc
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public boolean contains(FunctionalityProxyComponent fpc){
		
		//if the type of attribute don't coincide
		if(!fpc.containAttribute(attrType)) return false;
		
		BTreeData temp = new BTreeData(attrType);
		temp.setFPC(fpc);
		
		//if the value of the key isn't the vallue stored at the current node
		if(temp.compareTo(key)!=0) return false;
		
		FunctionalityProxyComponent FPCPtr;
		
		for (BTreeData dataPtr: this.data){
			FPCPtr = dataPtr.getFPC();
			 if(FPCPtr== fpc) return true;
		}
	 
		return false;
	}
	
	@SuppressWarnings("unchecked")
	public int addDataElement(BTreeData elem){
		//
		assert((this.data.isEmpty())||(elem.compareTo(this.key)==0)):"Attempt to insert a bad key value";
		
		if(!this.contains (elem.getFPC())){
			this.data.add((BTreeData)elem);
			return 1;
		}
		//throw new InvalidTypeException("Attempt do duplicate a BTreeNode element");
		return -1;
	}
	
	/**
	 * @param fpc
	 */
	public int addFPC(FunctionalityProxyComponent fpc){
		
			BTreeData elem = new BTreeData(this.attrType);
			elem.setFPC(fpc);		
			return this.addDataElement(elem);
	}
	
	/*public void addAlldata(ArrayList<Comparable> newdata){
		for (Comparable FPCPtr: this.data){
			addFPC(FPCPtr);
		} 
	}*/
	
	
	
	
	
}
